/*
        Cross Platform Core Code.

        Copyright(R) 2012-2015 Sumscope Software.
        All rights reserved.

        Using:
                CSPTimeSpan;
                CSPTime;
*/
#if !defined(__SP_TIME_H__)
#define __SP_TIME_H__

#include <time.h>

#include "../core.h"

/////////////////////////////////////////////////////////////////////////////
// CSPTimeSpan and CSPTime

class S_CORE_EXPORT CSPTimeSpan {
 public:
  // Constructors
  CSPTimeSpan();
  CSPTimeSpan(time_t time);
  CSPTimeSpan(long lDays, int nHours, int nMins, int nSecs);

  CSPTimeSpan(const CSPTimeSpan& timeSpanSrc);
  const CSPTimeSpan& operator=(const CSPTimeSpan& timeSpanSrc);

  // Attributes
  // extract parts
  long GetDays() const;  // total # of days
  long GetTotalHours() const;
  int GetHours() const;
  long GetTotalMinutes() const;
  int GetMinutes() const;
  long GetTotalSeconds() const;
  int GetSeconds() const;

  // Operations
  // time math
  CSPTimeSpan operator-(CSPTimeSpan timeSpan) const;
  CSPTimeSpan operator+(CSPTimeSpan timeSpan) const;
  const CSPTimeSpan& operator+=(CSPTimeSpan timeSpan);
  const CSPTimeSpan& operator-=(CSPTimeSpan timeSpan);
  bool operator==(CSPTimeSpan timeSpan) const;
  bool operator!=(CSPTimeSpan timeSpan) const;
  bool operator<(CSPTimeSpan timeSpan) const;
  bool operator>(CSPTimeSpan timeSpan) const;
  bool operator<=(CSPTimeSpan timeSpan) const;
  bool operator>=(CSPTimeSpan timeSpan) const;

  // #ifdef _UNICODE
  // 	// for compatibility with MFC 3.x
  // 	CSPString Format(LPCSTR pFormat) const;
  // #endif
  // 	CSPString Format(LPCTSTR pFormat) const;

  // serialization

 private:
  time_t m_timeSpan;
  friend class CSPTime;
};

class S_CORE_EXPORT CSPTime {
 public:
  // Constructors
  static CSPTime GetCurrentTime();
  static unsigned long GetTradeSecondsOfOneDay(bool isOpen930);
  //	static unsigned long	GetStockTimeNext( unsigned long dwDate, int
  //ktype, unsigned long dwYear = -1 );
  static time_t GetTimeTradeLatest(time_t tmTradeFirstToday);
  static double GetTimeTradeRatioOfOneDay(CSPTime tTradeLatestDay, CSPTime tNow,
                                          int nChangeDate);
  static time_t GetTradeOffsetToTime(int offset, time_t tmDay);
  static time_t GetLatestTradeTime(time_t tmNow);
  static bool InTradeTime(time_t tm, int nInflateSeconds = 180);
  static bool InCallAuctionTime(time_t tm, int nInflateSeconds = 180);
  static void SetDeltaTime(time_t delta);

  bool FromStockTimeDay(unsigned long dwDate);
  bool FromStockTimeMin(unsigned long dwDate, unsigned long dwYear = -1);
  bool FromStockTime(unsigned long dwDate, bool bDayOrMin,
                     unsigned long dwYear = -1);
  unsigned long ToBondTimeSecOrder(int nChangeDate);
  unsigned long ToBondTimeSecOrder915();
  unsigned long ToBondTimeSecOrder930();
  unsigned long ToStockTimeDay();
  unsigned long ToStockTimeMin();
  unsigned long ToStockTimeSecOrder(
      unsigned long dwStockExchange = -1 /*Ignored Now*/);
  unsigned long ToStockTime(bool bDayOrMin);

  CSPTime();
  CSPTime(time_t time);
  CSPTime(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec,
          int nDST = -1);
  CSPTime(unsigned short wDosDate, unsigned short wDosTime, int nDST = -1);
  CSPTime(const CSPTime& timeSrc);

  // 	CSPTime(const SYSTEMTIME& sysTime, int nDST = -1);
  // 	CSPTime(const FILETIME& fileTime, int nDST = -1);
  const CSPTime& operator=(const CSPTime& timeSrc);
  const CSPTime& operator=(time_t t);

  // Attributes
  struct tm* GetGmtTm(struct tm* ptm = NULL) const;
  struct tm* GetLocalTm(struct tm* ptm = NULL) const;
  // bool GetAsSystemTime(SYSTEMTIME& timeDest) const;

  time_t GetTime() const;
  int GetYear() const;
  int GetMonth() const;  // month of year (1 = Jan)
  int GetDay() const;    // day of month
  int GetHour() const;
  int GetMinute() const;
  int GetSecond() const;
  int GetWeekDay() const;
  int GetDayOfWeek() const;  // 1=Sun, 2=Mon, ..., 7=Sat

  // Operations
  // time math
  CSPTimeSpan operator-(CSPTime time) const;
  CSPTime operator-(CSPTimeSpan timeSpan) const;
  CSPTime operator+(CSPTimeSpan timeSpan) const;
  const CSPTime& operator+=(CSPTimeSpan timeSpan);
  const CSPTime& operator-=(CSPTimeSpan timeSpan);
  bool operator==(CSPTime time) const;
  bool operator!=(CSPTime time) const;
  bool operator<(CSPTime time) const;
  bool operator>(CSPTime time) const;
  bool operator<=(CSPTime time) const;
  bool operator>=(CSPTime time) const;

  // 	// formatting using "C" strftime
  // 	CSPString Format(LPCTSTR pFormat) const;
  // 	CSPString FormatGmt(LPCTSTR pFormat) const;
  //
  // #ifdef _UNICODE
  // 	// for compatibility with MFC 3.x
  // 	CSPString Format(LPCSTR pFormat) const;
  // 	CSPString FormatGmt(LPCSTR pFormat) const;
  // #endif

 private:
  time_t m_time;
  static time_t m_deltatime;
};

inline const CSPTimeSpan& CSPTimeSpan::operator=(
    const CSPTimeSpan& timeSpanSrc) {
  m_timeSpan = timeSpanSrc.m_timeSpan;
  return *this;
}
inline long CSPTimeSpan::GetDays() const {
  return (long)(m_timeSpan / (24 * 3600L));
}
inline long CSPTimeSpan::GetTotalHours() const {
  return (long)(m_timeSpan / 3600);
}
inline int CSPTimeSpan::GetHours() const {
  return (int)(GetTotalHours() - GetDays() * 24);
}
inline long CSPTimeSpan::GetTotalMinutes() const {
  return (long)(m_timeSpan / 60);
}
inline int CSPTimeSpan::GetMinutes() const {
  return (int)(GetTotalMinutes() - GetTotalHours() * 60);
}
inline long CSPTimeSpan::GetTotalSeconds() const { return (long)m_timeSpan; }
inline int CSPTimeSpan::GetSeconds() const {
  return (int)(GetTotalSeconds() - GetTotalMinutes() * 60);
}
inline CSPTimeSpan CSPTimeSpan::operator-(CSPTimeSpan timeSpan) const {
  return CSPTimeSpan(m_timeSpan - timeSpan.m_timeSpan);
}
inline CSPTimeSpan CSPTimeSpan::operator+(CSPTimeSpan timeSpan) const {
  return CSPTimeSpan(m_timeSpan + timeSpan.m_timeSpan);
}
inline const CSPTimeSpan& CSPTimeSpan::operator+=(CSPTimeSpan timeSpan) {
  m_timeSpan += timeSpan.m_timeSpan;
  return *this;
}
inline const CSPTimeSpan& CSPTimeSpan::operator-=(CSPTimeSpan timeSpan) {
  m_timeSpan -= timeSpan.m_timeSpan;
  return *this;
}
inline bool CSPTimeSpan::operator==(CSPTimeSpan timeSpan) const {
  return m_timeSpan == timeSpan.m_timeSpan;
}
inline bool CSPTimeSpan::operator!=(CSPTimeSpan timeSpan) const {
  return m_timeSpan != timeSpan.m_timeSpan;
}
inline bool CSPTimeSpan::operator<(CSPTimeSpan timeSpan) const {
  return m_timeSpan < timeSpan.m_timeSpan;
}
inline bool CSPTimeSpan::operator>(CSPTimeSpan timeSpan) const {
  return m_timeSpan > timeSpan.m_timeSpan;
}
inline bool CSPTimeSpan::operator<=(CSPTimeSpan timeSpan) const {
  return m_timeSpan <= timeSpan.m_timeSpan;
}
inline bool CSPTimeSpan::operator>=(CSPTimeSpan timeSpan) const {
  return m_timeSpan >= timeSpan.m_timeSpan;
}

inline const CSPTime& CSPTime::operator=(const CSPTime& timeSrc) {
  m_time = timeSrc.m_time;
  return *this;
}
inline const CSPTime& CSPTime::operator=(time_t t) {
  m_time = t;
  return *this;
}
inline time_t CSPTime::GetTime() const { return m_time; }
inline int CSPTime::GetYear() const {
  struct tm* pTime = GetLocalTm(NULL);
  if (pTime == NULL) return 0;
  return (pTime->tm_year) + 1900;
}
inline int CSPTime::GetMonth() const {
  struct tm* pTime = GetLocalTm(NULL);
  if (pTime == NULL) return 0;
  return pTime->tm_mon + 1;
}
inline int CSPTime::GetDay() const {
  struct tm* pTime = GetLocalTm(NULL);
  if (pTime == NULL) return 0;
  return pTime->tm_mday;
}
inline int CSPTime::GetHour() const {
  struct tm* pTime = GetLocalTm(NULL);
  if (pTime == NULL) return 0;
  return pTime->tm_hour;
}
inline int CSPTime::GetMinute() const {
  struct tm* pTime = GetLocalTm(NULL);
  if (pTime == NULL) return 0;
  return pTime->tm_min;
}
inline int CSPTime::GetSecond() const {
  struct tm* pTime = GetLocalTm(NULL);
  if (pTime == NULL) return 0;
  return pTime->tm_sec;
}
inline int CSPTime::GetDayOfWeek() const {
  struct tm* pTime = GetLocalTm(NULL);
  if (pTime == NULL) return 0;
  return pTime->tm_wday + 1;
}
inline int CSPTime::GetWeekDay() const {
  struct tm* pTime = GetLocalTm(NULL);
  if (pTime == NULL) return 0;
  return (((pTime->tm_wday - pTime->tm_yday) % 7 + pTime->tm_yday) / 7 * 1 + 2);
}
inline CSPTimeSpan CSPTime::operator-(CSPTime time) const {
  return CSPTimeSpan(m_time - time.m_time);
}
inline CSPTime CSPTime::operator-(CSPTimeSpan timeSpan) const {
  return CSPTime(m_time - timeSpan.m_timeSpan);
}
inline CSPTime CSPTime::operator+(CSPTimeSpan timeSpan) const {
  return CSPTime(m_time + timeSpan.m_timeSpan);
}
inline const CSPTime& CSPTime::operator+=(CSPTimeSpan timeSpan) {
  m_time += timeSpan.m_timeSpan;
  return *this;
}
inline const CSPTime& CSPTime::operator-=(CSPTimeSpan timeSpan) {
  m_time -= timeSpan.m_timeSpan;
  return *this;
}
inline bool CSPTime::operator==(CSPTime time) const {
  return m_time == time.m_time;
}
inline bool CSPTime::operator!=(CSPTime time) const {
  return m_time != time.m_time;
}
inline bool CSPTime::operator<(CSPTime time) const {
  return m_time < time.m_time;
}
inline bool CSPTime::operator>(CSPTime time) const {
  return m_time > time.m_time;
}
inline bool CSPTime::operator<=(CSPTime time) const {
  return m_time <= time.m_time;
}
inline bool CSPTime::operator>=(CSPTime time) const {
  return m_time >= time.m_time;
}

#endif  // __SP_TIME_H__
